﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;

namespace Transcend.DP3.Http
{
	public class FtpHelper
	{

		protected static log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

		public string Host { get; set; }
		public int Port { get; set; }
		public string User { get; set; }
		public string Password { get; set; }
		public int BufferSize { get; set; }
		public bool KeepAlive { get; set; }
		/// <summary>
		/// 使用二进制模式传输
		/// </summary>
		public bool BinaryMode { get; set; }
		/// <summary>
		/// 使用被动模式
		/// </summary>
		public bool UsePassive { get; set; }

		/* Construct Object */
		public FtpHelper(string host, string userName, string password, int port = 21)
		{
			BufferSize = 10240;
			BinaryMode = true;
			UsePassive = true;
			Host = host;
			Port = port;
			User = userName;
			Password = password;
		}

		/* Download File */
		public void download(string remoteFile, string localFile)
		{
			var ftpRequest = mkRequest(remoteFile);
			ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
			var ftpResponse = ftpRequest.GetResponse();
			/* Get the FTP Server's Response Stream */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Open a File Stream to Write the Downloaded File */
				using (FileStream localFileStream = new FileStream(localFile, FileMode.Create))
				{
					/* Buffer for the Downloaded Data */
					byte[] byteBuffer = new byte[BufferSize];
					int bytesRead = ftpStream.Read(byteBuffer, 0, BufferSize);
					/* Download the File by Writing the Buffered Data Until the Transfer is Complete */
					while (bytesRead > 0)
					{
						localFileStream.Write(byteBuffer, 0, bytesRead);
						bytesRead = ftpStream.Read(byteBuffer, 0, BufferSize);
					}
					/* Resource Cleanup */
				}
				ftpStream.Close();
				ftpResponse.Close();
				ftpRequest = null;
			}
		}

		/* Upload File */
		public void put(string remoteFile, string localFile)
		{
			/* Create an FTP Request */
			var ftpRequest = mkRequest(remoteFile);
			ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
			/* Establish Return Communication with the FTP Server */
			using (var ftpStream = ftpRequest.GetRequestStream())
			{

				/* Open a File Stream to Read the File for Upload */
				using (FileStream localFileStream = new FileStream(localFile, FileMode.Create))
				{
					/* Buffer for the Downloaded Data */
					byte[] byteBuffer = new byte[BufferSize];
					int bytesSent = localFileStream.Read(byteBuffer, 0, BufferSize);
					/* Upload the File by Sending the Buffered Data Until the Transfer is Complete */
					while (bytesSent != 0)
					{
						ftpStream.Write(byteBuffer, 0, bytesSent);
						bytesSent = localFileStream.Read(byteBuffer, 0, BufferSize);
					}
				}
				/* Resource Cleanup */
				ftpStream.Close();
				ftpRequest = null;
			}
		}

		/* Delete File */
		public void del(string file)
		{
			var ftpRequest = mkRequest(file);
			ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
			var ftpResponse = ftpRequest.GetResponse();
			/* Get the FTP Server's Response Stream */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Resource Cleanup */
				ftpResponse.Close();
				ftpRequest = null;
			}
		}

		/* Rename File */
		public void rename(string file, string newname)
		{
			var ftpRequest = mkRequest(file);
			ftpRequest.Method = WebRequestMethods.Ftp.Rename;
			/* Rename the File */
			ftpRequest.RenameTo = newname;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Resource Cleanup */
			ftpResponse.Close();
			ftpRequest = null;
		}

		/* Create a New Directory on the FTP Server */
		public void mkDir(string dir)
		{
			var ftpRequest = mkRequest(dir);
			ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Resource Cleanup */
			ftpResponse.Close();
			ftpRequest = null;
		}

		/* Get the Date/Time a File was Created */
		public string fCreateTime(string file)
		{
			/* Store the Raw Response */
			string fileInfo = string.Empty;
			var ftpRequest = mkRequest(file);
			ftpRequest.Method = WebRequestMethods.Ftp.GetDateTimestamp;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Establish Return Communication with the FTP Server */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Get the FTP Server's Response Stream */
				StreamReader ftpReader = new StreamReader(ftpStream);
				/* Read the Full Response Stream */
				fileInfo = ftpReader.ReadToEnd();
				/* Resource Cleanup */
				ftpReader.Close();
			}
			ftpResponse.Close();
			ftpRequest = null;
			/* Return File Created Date Time */
			return fileInfo;
		}

		/* Get the Size of a File */
		public string fsize(string file)
		{
			string fileInfo = string.Empty;
			var ftpRequest = mkRequest(file);
			ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Establish Return Communication with the FTP Server */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Get the FTP Server's Response Stream */
				using (StreamReader ftpReader = new StreamReader(ftpStream))
				{
					/* Store the Raw Response */

					/* Read the Full Response Stream */
					while (ftpReader.Peek() != -1) { fileInfo = ftpReader.ReadToEnd(); }
					/* Resource Cleanup */
				}
			}
			ftpResponse.Close();
			ftpRequest = null;
			/* Return File Size */
			return fileInfo;
		}

		/* List Directory Contents File/Folder Name Only */
		public string[] dir(string path)
		{
			string[] directoryList = null;
			string directoryRaw = null;

			/* Create an FTP Request */
			var ftpRequest = mkRequest(path);
			ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Establish Return Communication with the FTP Server */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Get the FTP Server's Response Stream */
				using (var ftpReader = new StreamReader(ftpStream))
				{
					/* Store the Raw Response */
					/* Read Each Line of the Response and Append a Pipe to Each Line for Easy Parsing */
					while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + "|"; }
					/* Resource Cleanup */
				}
			}
			ftpResponse.Close();
			ftpRequest = null;
			/* Return the Directory Listing as a string Array by Parsing 'directoryRaw' with the Delimiter you Append (I use | in This Example) */
			directoryList = directoryRaw.Split("|".ToCharArray());
			/* Return an Empty string Array if an Exception Occurs */
			return directoryList;
		}

		/* List Directory Contents in Detail (Name, Size, Created, etc.) */
		public string[] dirDetail(string path)
		{
			string directoryRaw = null;
			string[] directoryList = null;
			var ftpRequest = mkRequest(path);
			ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
			/* Establish Return Communication with the FTP Server */
			var ftpResponse = ftpRequest.GetResponse() as FtpWebResponse;
			/* Establish Return Communication with the FTP Server */
			using (var ftpStream = ftpResponse.GetResponseStream())
			{
				/* Get the FTP Server's Response Stream */
				using (var ftpReader = new StreamReader(ftpStream))
				{
					/* Read Each Line of the Response and Append a Pipe to Each Line for Easy Parsing */
					while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + "|"; }
					/* Resource Cleanup */
					ftpReader.Close();
				}
			}
			ftpResponse.Close();
			/* Return the Directory Listing as a string Array by Parsing 'directoryRaw' with the Delimiter you Append (I use | in This Example) */
			directoryList = directoryRaw.Split("|".ToCharArray());
			return directoryList;
		}

		protected FtpWebRequest mkRequest(string path)
		{
			Logger.Debug("创建FTP连接");
			Uri uri = new UriBuilder("ftp", Host, Port, path).Uri;
			var ftpRequest = FtpWebRequest.Create(uri) as FtpWebRequest;
			/* Log in to the FTP Server with the User Name and Password Provided */
			ftpRequest.Credentials = new NetworkCredential(User, Password);
			/* When in doubt, use these options */
			ftpRequest.UsePassive = UsePassive;
			ftpRequest.KeepAlive = KeepAlive;

			ftpRequest.UseBinary = BinaryMode;
			return ftpRequest;
		}

	}
}
